'''
Created on Aug 16, 2010

@author: dexen
'''
import os

import radiance
import energyplus
import daysimfunc

class Surface(object):
    def __init__(self, name, points, material):
        self.name = name
        self.points = points
        self.material = material
    
class RadGeom(object):
    def __init__(self, ):
        self.surfaces = []
        self.total_sensor_pts = None
        self.result_file = None
        self.sensor_file_path = None
        self.rad_file_path = None
        self.hea_result = None
        self.hea_filename = None
        self.direction = None
        self.rad_mat_file = None  
             
    def add_sensor_points(self, sensor_pt_list, direction):
        self.total_sensor_pts = sensor_pt_list
        self.direction = direction
        
    def create_rad(self, basefile_path, filename, interior = True):
        radout = os.path.join(basefile_path, "radout")
        rad_file_path = os.path.join(radout, filename + "_out.rad")
        #CREATE THE RADOUT DIRECTORY FOR STORING THE OUTPUT FILE 
        if not os.path.isdir(radout):
            os.mkdir(radout)
        #CREATE THE .RAD FILE 
        rad_building_data = []
        rad_file = open(rad_file_path,  "w")
        for surface in self.surfaces:
            if interior == True:
                rad_data = surface.rad()
            else:
                rad_data = surface.rad(interior = False)
            rad_building_data.append(rad_data)
            
        for data in rad_building_data:
            rad_file.write(data)
        rad_file.close()
        #CREATE SENSOR FILE 
        sensor_file_path = os.path.join(radout, filename + "_out.pts")
        sensor_file = open(sensor_file_path,  "w")
        sensor_pts_data = radiance.write_sensor_file(self.total_sensor_pts, self.direction)
        sensor_file.write(sensor_pts_data)
        sensor_file.close()
        self.sensor_file_path = sensor_file_path
        self.rad_file_path = rad_file_path 
        self.rad_mat_file = os.path.join(basefile_path, filename + ".mat")
        return radout, sensor_file_path, rad_file_path 
    
    def execute_rad(self, basefile_path, filename): 
        radout = self.create_rad(basefile_path, filename)[0]
        sensor_file_path = self.create_rad(basefile_path, filename)[1]
        rad_file_path = self.create_rad(basefile_path, filename)[2]
        #EXECUTE RADIANCE 
        oconv_file = os.path.join(radout, filename + "_out.oconv")
        sensors_file = sensor_file_path
        result_file = os.path.join(radout, filename + "_out.txt")
        #create oconv file
        material_file = os.path.join(basefile_path, filename + ".mat")
        sky_file = os.path.join(basefile_path, filename + "_sky.rad")
        command1 = "oconv " + "'" + material_file + "'" + " "\
        + "'" + sky_file + "'" + " " + "'" + rad_file_path + "'"\
        + " " + ">" + " " + "'" + oconv_file + "'"
        os.system(command1)
        #execute rtrace 
        command2 = "rtrace -h -w -I+ -ab 3 " + "'" +  oconv_file + "'" + " " + " < " + " " + "'" + sensors_file + "'"\
        + " " + " > " + " " + "'" + result_file + "'" 
        os.system(command2)
        self.result_file = result_file 
    
    def eval_rad(self, result_category):
        if self.result_file == None:
            raise Exception
        
        illum_results = open(self.result_file, "r")
        illum_res_list = []
        irradiance_list = []
        for illum_result in illum_results:
            words  = illum_result.split()
            numbers = map(float, words)
            #INSOLATION RESULTS 
            irradiance = round((0.265 * numbers[0]) + (0.670 * numbers[1]) + (0.065 * numbers[2]), 1)
            irradiance_list.append(irradiance)
            #ILLUMINANCE RESULTS            
            illuminance = irradiance * 179
            illum_res_list.append(illuminance)
            
        if result_category == "illuminance":
            return illum_res_list  
        if result_category == "insolation":
            return irradiance_list
        
    def execute_hea(self, basefile_path, filename, bin_dir):
        if self.sensor_file_path == None or self.rad_file_path == None:
            raise NameError("run .create_rad function before running .execute_hea function")
        
        #CREATE THE NECCESSARY FOLDERS FOR THE OUTPUT OF THE VARIOUS RESULTS
        heaout = os.path.join(basefile_path, "heaout/")
        hea_file_path = os.path.join(heaout, filename + "_out.hea")
        
        if not os.path.isdir(heaout):
            os.mkdir(heaout)
        sub_hea_folders = ["pts", "rad", "res","tmp", "wea"]
        for folder in range(len(sub_hea_folders)):
            sub_hea_folder = sub_hea_folders[folder]
            sub_hea_folders_path = os.path.join(heaout,sub_hea_folder)
            if not os.path.isdir(sub_hea_folders_path):
                os.mkdir(sub_hea_folders_path)
            if os.path.isdir(sub_hea_folders_path):
                files_in_dir = os.listdir(sub_hea_folders_path)
                for file in files_in_dir:
                    rmv_path = os.path.join(sub_hea_folders_path, file)
                    os.remove(rmv_path)
        
        #APPEND THE BASEFILE 
        base_filepath = os.path.join(basefile_path, filename + ".hea") 
        base_file = open(base_filepath, "r")
        base_stuff = base_file.read()
        base_file.close()
        hea_data = []
        hea_data.append(base_stuff)
        
        #WRITE THE HEA INFORMATION 
        tmp_dir = os.path.join(heaout, "tmp/")
        proj_info = daysimfunc.write_proj_info(filename, heaout, tmp_dir)
        hea_data.append(proj_info)
        
        #WRITE THE WEATHER DATA 
        wea_file_dir = '/home/dexen/daysim/wea/SGP_Singapore.486980_IWEC_60min.wea' # in order to change the weather file input the 60min .wea dir, do the conversion from epw to wea using execute_epw2wea(bin_dir, source_file, destination_file)
        short_wea_name = "SGP_Singapore.486980_IWEC_5min.wea" # change the output .wea name respectively 
        weather_data = daysimfunc.write_weather_data(wea_file_dir, 0.2, short_wea_name)
        hea_data.append(weather_data)
        
        #WRITE THE GEOMETRY INFO
        sensor_file_path = self.sensor_file_path 
        rad_file_path = self.rad_file_path 
        rad_file_dir_list = [self.rad_mat_file, rad_file_path]
        geometry_data = daysimfunc.write_geometry_info(filename, sensor_file_path, rad_file_dir_list)
        hea_data.append(geometry_data)
        
        #WRITE THE RESULTS INFO
        result_data = daysimfunc.write_result_file(filename)
        hea_data.append(result_data)
        
        #WRITE THE RESULT FILE 
        hea_file = open(hea_file_path,  "w")
        for data in hea_data:
            hea_file.write(data)
        hea_file.close()
        
        #EXECUTE DAYSIM
        os.chdir(bin_dir)
        command1 =  "./ds_shortterm " +  hea_file_path
        os.system(command1)
        command2 = "./radfiles2daysim " +  "'" + hea_file_path +"'" + " -g -m -d"
        os.system(command2)
        command3 = "./gen_dc " +  "'" + hea_file_path +"'"
        os.system(command3)
        command4 = "./ds_illum " +  "'" + hea_file_path +"'" 
        os.system(command4)
        command5 = "./gen_directsunlight " +  "'" + hea_file_path +"'" 
        os.system(command5)
        command6 = "./ds_autonomy " +  "'" + hea_file_path +"'" 
        os.system(command6)
        
        self.hea_result = os.path.join(heaout, "res")
        self.hea_filename = filename
        
    def eval_hea(self):
        if self.hea_result == None or self.hea_filename == None :
            raise Exception
        da_path = os.path.join(self.hea_result,self.hea_filename + ".da")
        da_results = open(da_path, "r")
        da_result_stuff = da_results.readlines()
        num_da_list = []
        #daysim results processing average the DA
        for line in range(len(da_result_stuff)-2): 
            lines =  da_result_stuff[2+line][78:83] 
            numbers_da = float(lines)
            num_da_list.append(round(numbers_da, 1))
        return num_da_list
    
class RadSurface(Surface):
    def __init__(self, name, points, material, radgeom):
        super(RadSurface, self).__init__(name,  points, material)
        self.radgeom = radgeom
        radgeom.surfaces.append(self)
        
    def rad(self, interior = True):
        name = self.name
        material = self.material
        points = self.points[:]
        if interior == True:
            points.reverse()
        return radiance.write_surface(name, material, points)
        
class IdfGeom(object):
    
    def __init__(self):
        self.zones = []
        self.building_data = None
        self.result_file = None
        self.filename = None
        #SEARCH FOR OVERLAPPING surfaces
    
    def execute_idf(self, basefile_path, filename):
        total_srfs= []
        total_sub = []
        same_srfs= []
        for zone in self.zones:
            for srf in zone.surfaces:
                total_srfs.append(srf)
            for subsrf in zone.subsurfaces:
                total_sub.append(subsrf)
        counter = 0
        for total_srf in total_srfs:
            for num_srf in range(len(total_srfs)):
                if num_srf <= len(total_srfs)-(2+counter):
                    total_srf_rev = total_srfs[num_srf+1+counter].points[:]
                    total_srf_rev.reverse()
                    if total_srf.points == total_srfs[num_srf +(1+counter)].points or total_srf.points == total_srf_rev:
                        total_srfs[num_srf +(1+counter)].boundary = "Surface" 
                        total_srfs[num_srf +(1+counter)].boundary_obj = total_srf.name 
                        total_srfs[num_srf +(1+counter)].sun_exp = "NoSun"
                        total_srfs[num_srf +(1+counter)].win_exp = "NoWind"
                        same_srfs.append(total_srfs[num_srf +(1+counter)])
                        if counter == len(total_srfs)-(2+counter):
                            total_srf.boundary = "Surface" 
                            total_srf.boundary_obj = total_srfs[num_srf +(1+counter)].name 
                            total_srf.sun_exp = "NoSun"
                            total_srf.win_exp = "NoWind"
                            same_srfs.append(total_srf)
            counter +=1
            
        zones_data = ""
        total_srfs_data = ""
        total_sub_data = ""
        for zone in self.zones:
            zones_data = zones_data + zone.idf()
        for srfs in total_srfs:
            total_srfs_data = total_srfs_data + srfs.idf()
        for subsrfs in total_sub:
            total_sub_data = total_sub_data + subsrfs.idf()
        building_data = zones_data + total_srfs_data + total_sub_data
        
        
        idfout = os.path.join(basefile_path, "idfout")
        idf_file_path = os.path.join(idfout, filename + "_out.idf")
        #CREATE THE IDFOUT DIRECTORY FOR STORING THE OUTPUT FILE 
        if not os.path.isdir(idfout):
            os.mkdir(idfout)
        #CREATE THE .IDF FILE
        idf_data = []
        base_idf_file = os.path.join( basefile_path, filename + ".idf")
        #read all the stuff in the base idf file 
        base_idf_file = open(base_idf_file,  "r")
        base_stuff = base_idf_file.read()
        base_idf_file.close()
        idf_data.append(base_stuff)
        for _ in range(10):
            idf_data.append("! ======================================== \n")
        idf_data.append(building_data)
        
        idf_file = open(idf_file_path,  "w")
        for data in idf_data:
            idf_file.write(data)
        idf_file.close()
        #EXECUTE ENERGYPLUS 
        
        #prev_dir = os.getcwd()
        #target_dir = os.path.join("/home", "dexen", "EnergyPlus", "EnergyPlus-5-0-0", "bin")
        #print "The energyplus dir is", target_dir
        #os.chdir(target_dir)
        print "IDF FILE PATH is", idf_file_path, "............................."
        command = "runenergyplus " +  idf_file_path + " SGP_Singapore.486980_IWEC.epw > ep_out.txt"
        os.system(command)
        f = open("ep_out.txt", "r")
        print f.read()
        f.close()        
        self.result_file = os.path.join(idfout, "Output")
        self.filename = filename
        #os.chdir(prev_dir)
        
        
    def eval_idf(self, result_category):
        if self.result_file == None:
            raise Exception
        if result_category == "energytransfer":
            result_path = os.path.join(self.result_file, self.filename + "_out" + "Meter.csv")
            energy_results = open(result_path, "r")
            energy_list = []
            energy_results.next()
            for energy_result in energy_results:
                words = energy_result.split (",")
                numbers = map(float, words[1:])
                energy_list.append(numbers)
            total = (sum(energy_list[0]) + sum(energy_list[1])) / 22
            total = total * 2.77777777777778E-07 # convert from J to KWh
            return total
          
class IdfZone(object):
    def __init__(self, name, idf):
        self.name = name
        self.Idf = idf
        self.surfaces = []
        self.subsurfaces = []
        idf.zones.append(self)
        
    def add_surface(self,  surface):
        surface.zone = self.name
        self.surfaces.append(surface)
        
    def add_window(self,  window):
        self.subsurfaces.append(window)
        
    def add_shade(self,  shade):
        self.subsurfaces.append(shade)
        
    def idf(self):
        name = self.name 
        zone_data = energyplus.write_ep_zone(name)
        return zone_data
        
class IdfZoneSurface(Surface):
    def __init__(self, name, points, material, type):
        super(IdfZoneSurface, self).__init__(name,  points, material)
        self.zone = None 
        self.boundary = "Outdoors" 
        self.boundary_obj = "" 
        self.sun_exp = "SunExposed" 
        self.win_exp = "WindExposed"
        self.type = type
        
    def idf(self):
        total_z=[]
        for point in self.points:
            total_z.append(point[2])
            
        if self.type == "Floor" and sum(total_z) == 0:
            self.boundary = "Ground"
            self.sun_exp =  "NoSun"
            self.win_exp = "NoWind"
            
        name = self.name
        type = self.type
        construction = self.material
        zone = self.zone
        boundary = self.boundary
        boundary_object = self.boundary_obj
        sun_exp = self.sun_exp
        wind_exp = self.win_exp
        points = self.points
        
        surface_data = energyplus.write_ep_surface(name, type,construction, zone, 
                                                boundary,boundary_object, sun_exp, wind_exp, points)
        return surface_data
                                              
class IdfSubSurface(Surface):
    def __init__(self, name, points, material, host_srf):
        super(IdfSubSurface,self).__init__(name,  points, material)
        self.host_srf = host_srf
        self.transmittance = "" 

class IdfWindow(IdfSubSurface):
    
    def idf(self):
        if self.host_srf == None:
            raise Exception
        
        win_name = self.name 
        win_construction = self.material
        build_surface = self.host_srf
        win_shading = ""
        win_frame = ""
        win_points = self.points
        window_data = energyplus.write_ep_window(win_name, win_construction, build_surface, win_shading, win_frame, win_points)   
        return window_data


class IdfShade(IdfSubSurface):
    
    def idf(self):
        if self.host_srf == None:
            raise Exception
        shade_name = self.name 
        base_surface = self.host_srf
        transmittance = self.transmittance
        shade_points = self.points
        shade_data = energyplus.write_ep_zone_shade(shade_name, base_surface, transmittance, shade_points)
        return shade_data

